﻿#include "Renderer/Shader.h"
#include<glm/gtc/type_ptr.hpp>

namespace ArsEngine
{
    Shader::Shader(const char* vertexShader, const char* fragmentShader)
    {
        GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);

        const char* source = vertexShader;
        glShaderSource(vertexShaderID, 1, &source, 0);

        glCompileShader(vertexShaderID);

        GLint isCompiled = 0;
        glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &isCompiled);

        if (isCompiled == GL_FALSE)
        {
            GLint maxLength = 0;
            glGetShaderiv(vertexShaderID, GL_INFO_LOG_LENGTH, &maxLength);

            std::vector<GLchar> infoLog(maxLength);
            glGetShaderInfoLog(vertexShaderID, maxLength, &maxLength, &infoLog[0]);

            glDeleteShader(vertexShaderID);

            AN_CORE_ERROR("Vertex Shader Compilation Error: {0}", infoLog.data());
            AN_ASSERT(false, "Vertex Shader Compilation Error");

            return;
        }

        GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
        source = fragmentShader;
        glShaderSource(fragmentShaderID, 1, &source, 0);

        glCompileShader(fragmentShaderID);

        isCompiled = 0;
        glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &isCompiled);

        if (isCompiled == GL_FALSE)
        {
            GLint maxLength = 0;
            glGetShaderiv(fragmentShaderID, GL_INFO_LOG_LENGTH, &maxLength);

            std::vector<GLchar> infoLog(maxLength);
            glGetShaderInfoLog(fragmentShaderID, maxLength, &maxLength, &infoLog[0]);

            glDeleteShader(fragmentShaderID);

            AN_CORE_ERROR("Fragment Shader Compilation Error: {0}", infoLog.data());
            AN_ASSERT(false, "Fragment Shader Compilation Error");

            return;
        }

        m_RendererID = glCreateProgram();

        auto programID = m_RendererID;
        glAttachShader(programID, vertexShaderID);
        glAttachShader(programID, fragmentShaderID);
        glLinkProgram(programID);

        GLint isLinked = 0;
        glGetProgramiv(programID, GL_LINK_STATUS, (int*)&isLinked);

        if (isLinked == GL_FALSE)
        {
            GLint maxLength = 0;
            glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &maxLength);

            std::vector<GLchar> infoLog(maxLength);
            glGetProgramInfoLog(programID, maxLength, &maxLength, &infoLog[0]);

            glDeleteProgram(programID);
            glDeleteShader(vertexShaderID);
            glDeleteShader(fragmentShaderID);

            AN_CORE_ERROR("Shader Linking Error: {0}", infoLog.data());
            AN_ASSERT(false, "Shader Linking Error");

            return;
        }

        glDeleteShader(vertexShaderID);
        glDeleteShader(fragmentShaderID);

    }

    Shader::~Shader()
    {
        glDeleteProgram(m_RendererID);
    }

    void Shader::Bind() const
    {
        glUseProgram(m_RendererID);
    }

    void Shader::Unbind() const
    {
        glUseProgram(0);
    }

    void Shader::SetUniformMat4f(const std::string& name, const glm::mat4& value) const
    {
        GLint location = glGetUniformLocation(m_RendererID, name.c_str());
        glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));       
    }
}
